package tcln.gxtx.client.utils.lang;

import com.google.gwt.i18n.client.NumberFormat;

/**
 * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
 */
public final class GwtNumberUtils {

    /**
     * Default format pattern for integer values.
     */
    public static final String INTEGER_FORMAT = "#,###";

    /**
     * Default format pattern for decimal values.
     */
    public static final String DECIMAL_FORMAT = "#,##0.00";

    /**
     * Formats a given numeric value using default format pattern for decimal numbers.
     * 
     * @param value
     *            Value to format.
     * @return formatted value or empty string if given value is <code>null</code>.
     */
    public static String formatDecimal(Number value) {
        if (value != null) {
            return NumberFormat.getFormat(DECIMAL_FORMAT).format(value.doubleValue());
        }
        return "";
    }

    /**
     * Formats a given numeric value using default format pattern for integer numbers.
     * 
     * @param value
     *            Value to format.
     * @return formatted value or empty string if given value is <code>null</code>.
     */
    public static String formatInteger(Number value) {
        if (value != null) {
            return NumberFormat.getFormat(INTEGER_FORMAT).format(value.intValue());
        }
        return "";
    }

    /**
     * Ensures that given integer value is not null by converting it to zero in this case.
     * 
     * @param value
     * @return
     */
    public static int nullToZero(Integer value) {
        return value != null ? value : 0;
    }

    /**
     * Checks if given numeric object has a value or not. A number is considered "has value" if it's not
     * <code>null</code> and is not zero.
     * 
     * @param value
     * @return
     */
    public static boolean hasValue(Number value) {
        boolean ok = value != null;

        if (ok) {
            if (value instanceof Double || value instanceof Float) {
                return value.doubleValue() != 0d;
            } else if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
                return value.intValue() != 0;
            } else if (value instanceof Long) {
                return value.longValue() != 0l;
            }
        }
        return false;
    }

    /**
     * Checks if given numeric value is positive or not.
     * 
     * @param value
     * @return
     */
    public static boolean isPositive(Number value) {
        return hasValue(value) && doCheckNumberRangeBaseOnZero(value, 1);
    }

    /**
     * Checks if given numeric value is negative or not.
     * 
     * @param value
     * @return
     */
    public static boolean isNegative(Number value) {
        return hasValue(value) && doCheckNumberRangeBaseOnZero(value, -1);
    }

    /**
     * Checks if given numeric value is zero (not <code>null</code>).
     * 
     * @param value
     * @return
     */
    public static boolean isZero(Number value) {
        return doCheckNumberRangeBaseOnZero(value, 0);
    }

    private static boolean doCheckNumberRangeBaseOnZero(Number value, int direction) {
        boolean passed = value != null;

        if (passed) {
            if (value instanceof Double || value instanceof Float) {
                passed = direction == 0 ? value.doubleValue() == 0d : (direction > 0 ? value.doubleValue() > 0 : value
                        .doubleValue() < 0);
            } else if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
                passed = direction == 0 ? value.intValue() == 0d : (direction > 0 ? value.intValue() > 0 : value
                        .intValue() < 0);
            } else if (value instanceof Long) {
                passed = direction == 0 ? value.longValue() == 0d : (direction > 0 ? value.longValue() > 0 : value
                        .longValue() < 0);
            }
        }

        return passed;
    }
}
